#include "d3dApp.h"
#include "l_systems.h"
#include "camera.h"
#include "FPPCamera.h"
#include "tree.h"
#include "terrain.h"
#include "sphere.h"
#include "RandomTexture.h"
#include "terrainPlants.h"



class myApp : public D3DApp
{
public:
	myApp(HINSTANCE hInstance);
	~myApp();

	void InitApp();
	void OnResize();// reset projection/etc
	void UpdateScene(float dt);
	void DrawScene(); 
	void Controls();

private:
	

	
	ID3D10InputLayout*      g_pVertexLayout;

	Tree *tree;
	Tree *tree2;
	Tree *tree3;
	Sphere * sphere;
	Terrain * terrain;
	TerrainPlants * m_TerrainPlants;
	RandomTexture * m_RandomTexture;
	
	//Textures
	ID3D10ShaderResourceView * m_GrassTexture;
	ID3D10ShaderResourceView * m_LeafTexture;

	float m_Time;
	D3DXVECTOR3 m_LightDirection; //light direction


};

myApp::myApp(HINSTANCE hInstance):D3DApp(hInstance)
{
	mMainWndCaption="Proceduralne generowanie geometri. DirectX,CUDA,HLSL";
	m_ShaderPath="\Shader2.fx";
	mClearColor=D3DXCOLOR(120.0/255,170.0/255,230.0/255,1);

}

myApp::~myApp()
{
	
}


void myApp::DrawScene()
{
	D3DApp::DrawScene();

	// Set the input layout
	md3dDevice->IASetInputLayout( g_pVertexLayout );

	//draw objects form scene object manager
	m_SceneObjectManager->Draw();
	


}




void myApp::InitApp()
{
	D3DApp::initApp();
	
	
	m_Camera=new FPPCamera();
	m_RandomTexture= new RandomTexture(md3dDevice);
	
	
	m_LightDirection=D3DXVECTOR3(1,1,1);


	// Obtain the technique
	m_ShaderManager->addTechnique( "Zlants" );
	m_ShaderManager->addTechnique( "TreeBranch" );
	m_ShaderManager->addTechnique( "TreeLeaf" );
	m_ShaderManager->addTechnique( "TreeLeaf2" );
	m_ShaderManager->addTechnique( "Terrain" );
	m_ShaderManager->addTechnique( "Sky" );
	

	//create grass texture
	m_ShaderManager->addResourceVariable("txGrass");
	D3DX10CreateShaderResourceViewFromFile( md3dDevice, "grass1.png", NULL, NULL, &m_GrassTexture, NULL );
	m_ShaderManager->setResourceVariable("txGrass",m_GrassTexture);

	//create leaf texture
	m_ShaderManager->addResourceVariable("txLeaf");
	D3DX10CreateShaderResourceViewFromFile( md3dDevice, "leaf.png", NULL, NULL, &m_GrassTexture, NULL );
	m_ShaderManager->setResourceVariable("txLeaf",m_GrassTexture);

	//create leaf texture
	m_ShaderManager->addResourceVariable("txLeaf2");
	D3DX10CreateShaderResourceViewFromFile( md3dDevice, "leaf2.png", NULL, NULL, &m_GrassTexture, NULL );
	m_ShaderManager->setResourceVariable("txLeaf2",m_GrassTexture);



	// Define the input layout
	D3D10_INPUT_ELEMENT_DESC layout[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 32, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "BINORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 44, D3D10_INPUT_PER_VERTEX_DATA, 0 },

	};
	UINT numElements = sizeof( layout ) / sizeof( layout[0] );

	// Create the input layout
	D3D10_PASS_DESC PassDesc;
	m_ShaderManager->getTechniqueByName("TreeBranch")->GetPassByIndex( 0 )->GetDesc( &PassDesc );
	md3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature,
		PassDesc.IAInputSignatureSize, &g_pVertexLayout );



	m_ShaderManager->addVectorVariable("vLightDirection");
	m_ShaderManager->addResourceVariable("txRandomNumbers");

	m_ShaderManager->setVectorVariable("vLightDirection", static_cast<float*>(m_LightDirection));
	m_ShaderManager->setResourceVariable("txRandomNumbers", m_RandomTexture->GetRandomTexture());


	LSystem S;

	S.SetStart("A");

	S.AddRule('A',"FFF+CF>F+B+++BF+CF/+BF+++B>F+D++BF<+DF+B+DF>+CF");
	S.AddRule('B',"[<<FD++CF++C/FDF++C\\F]");
	S.AddRule('C',"[<<FD/FD+<FD]");
	S.AddRule('D',"[>>>F]++[>>>F]++[>>>F]++[>>>F]++[>>>F]++[>>>F]");



	LSystem D;

	D.SetStart("A");
	D.AddRule('A',"F>F<[<F/FB][>F\\FB]");
	D.AddRule('B',"[FC<FC+>FC][>>>FC/FCFC]++[>>>FCFCFC]++[>>>>FCFCFC]++[>>>FCFCFC]++[>>>>FCFCFC]++[>>FCFCFC]");
	D.AddRule('C',"[>>>F]++[>>>F]++[>>>F]++[>>>F]++[>>>F]++[>>>F]");

	LSystem F;

	F.SetStart("A");
	F.AddRule('A',"FF>FFF<[<F/FB][>F\\FB]");
	F.AddRule('B',"[FC<FC+>FC][>>>FC/FCFC]++[>>>FCFCFC]++[>>>>FCFCFC]++[>>>FCFCFC]++[>>>>FCFCFC]++[>>FCFCFC]");
	F.AddRule('C',"[>>>F]++[>>>F]++[>>>F]++[>>>F]++[>>>F]++[>>>F]");



	tree=new Tree(md3dDevice,10);
	tree->generateLSys(&S,6,4.0f);		
	tree->generateCuda(8,0.07f);
	tree->generateLeafsCUDA(10,0.4f);

	tree2=new Tree(md3dDevice,10);
	tree2->generateLSys(&D,3,5.0f);		
	tree2->generateCuda(6,0.4f);
	tree2->generateLeafsCUDA(8,0.7f);

	tree3=new Tree(md3dDevice,10);
	tree3->generateLSys(&F,3,7.0f);		
	tree3->generateCuda(6,0.7f);
	tree3->generateLeafsCUDA(12,0.7f);


	terrain=new Terrain(md3dDevice,20, 30);

	sphere=new Sphere(md3dDevice,10,1000);

	m_TerrainPlants = new TerrainPlants(md3dDevice, 500);
	m_TerrainPlants->Generate(terrain,D3DXVECTOR2(0,500),D3DXVECTOR2(500,0));

	
	D3DXQUATERNION rotation;
	D3DXQuaternionIdentity(&rotation);

	m_SceneObjectManager->AddObject(terrain->GetTerrain(), "Terrain",D3DXVECTOR3(0,0,0),rotation);
	m_SceneObjectManager->AddObject(sphere->GetSphere(), "Sky",D3DXVECTOR3(0,0,0),rotation);
	m_SceneObjectManager->AddObject(m_TerrainPlants->GetDrawableObject(),"Zlants",D3DXVECTOR3(0,0,0),rotation);

	
	
	for(int i=0; i<15; i++)
	{
		float x= rand()%500;
		float z= rand()%500;

		D3DXQuaternionRotationYawPitchRoll(&rotation, (float)(rand()%100)/50,0,0);

		m_SceneObjectManager->AddObject(tree->GetLeafs(), "TreeLeaf",D3DXVECTOR3(x,terrain->GetHeight(x,z),z),rotation);
		m_SceneObjectManager->AddObject(tree->GetBranches(),"TreeBranch",D3DXVECTOR3(x,terrain->GetHeight(x,z),z),rotation);
	}

	for(int i=0; i<15; i++)
	{
		float x= rand()%500;
		float z= rand()%500;
	
		D3DXQuaternionRotationYawPitchRoll(&rotation, (float)(rand()%100)/50,0,0);

		m_SceneObjectManager->AddObject(tree2->GetLeafs(), "TreeLeaf2",D3DXVECTOR3(x,terrain->GetHeight(x,z)-1.0f,z),rotation);
		m_SceneObjectManager->AddObject(tree2->GetBranches(),"TreeBranch",D3DXVECTOR3(x,terrain->GetHeight(x,z)-1.0f,z),rotation);
	}

	for(int i=0; i<15; i++)
	{
		float x= rand()%500;
		float z= rand()%500;

		D3DXQuaternionRotationYawPitchRoll(&rotation, (float)(rand()%100)/50,0,0);

		m_SceneObjectManager->AddObject(tree3->GetLeafs(), "TreeLeaf",D3DXVECTOR3(x,terrain->GetHeight(x,z)-1.0f,z),rotation);
		m_SceneObjectManager->AddObject(tree3->GetBranches(),"TreeBranch",D3DXVECTOR3(x,terrain->GetHeight(x,z)-1.0f,z),rotation);
	}

	


	

}

void myApp::OnResize()
{
	D3DApp::OnResize();
}

void myApp::UpdateScene(float dt)
{
	D3DApp::UpdateScene(dt);
	Controls();

	//update camera height

	D3DXVECTOR3 position=dynamic_cast<FPPCamera*>(m_Camera)->GetAtPosition();

	dynamic_cast<FPPCamera*>(m_Camera)->SetAtPosition(D3DXVECTOR3(position.x,terrain->GetHeight(position.x,position.z)+10.0f,position.z));

}

void myApp::Controls()
{
	m_MouseManager->Update();
	D3DXVECTOR3 mouseMovement=m_MouseManager->GetMouseMovement();
	float moveMultiplier=100.0f;
	
	//Camera rotation
	if(mouseMovement.x<0)
		dynamic_cast<FPPCamera*>(m_Camera)->RotateY(mouseMovement.x/moveMultiplier);
	else if(mouseMovement.x>0)
		dynamic_cast<FPPCamera*>(m_Camera)->RotateY(mouseMovement.x/moveMultiplier);
	
	if(mouseMovement.y<0)
		dynamic_cast<FPPCamera*>(m_Camera)->RotateX(-mouseMovement.y/moveMultiplier);
	else if(mouseMovement.y>0)
		dynamic_cast<FPPCamera*>(m_Camera)->RotateX(-mouseMovement.y/moveMultiplier);


	//Move camera
	if(m_MouseManager->MouseButtonDown(1))
		dynamic_cast<FPPCamera*>(m_Camera)->move(D3DXVECTOR3(0,0,-2.0f));


	

		



}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
{



	myApp application(hInstance);

	application.InitApp();

	return application.Run();
}